using System.Collections.Specialized;
using System.Web.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Be.Timvw.Framework.Web.Security
{
    [TestClass]
    public class WhenUsingOneTimePasswordMembershipProvide
    {
        #region Infrastructure for all tests in this class

        private IMembershipProvider membershipProvider;
        private MockRepository repository;

        [TestInitialize]
        public void BeforeEachMethod()
        {
            this.repository = new MockRepository();
            this.membershipProvider = this.repository.StrictMock<IMembershipProvider>();
            MockMembershipProviderWrapper.MembershipProvider = this.membershipProvider;
        }

        [TestCleanup]
        public void AfterEachMethod()
        {
            MockMembershipProviderWrapper.MembershipProvider = null;

            this.repository.Playback().Dispose();
            this.repository.VerifyAll();
            this.repository = null;
        }

        public NameValueCollection GetConfig()
        {
            NameValueCollection config = new NameValueCollection();
            config.Add(OneTimePasswordMembershipProvider.ProviderTypeKey, typeof(MockMembershipProviderWrapper).AssemblyQualifiedName);
            return config;
        }

        public OneTimePasswordMembershipProvider CreateAndInitializeOneTimePasswordMembershipProvider()
        {
            return this.CreateAndInitializeOneTimePasswordMembershipProvider("/", this.GetConfig());
        }

        public OneTimePasswordMembershipProvider CreateAndInitializeOneTimePasswordMembershipProvider(string name, NameValueCollection config)
        {
            string expectedName = name;
            NameValueCollection expectedConfig = config;

            using(this.repository.Record())
            {
                Expect.Call(delegate { this.membershipProvider.Initialize(expectedName, expectedConfig); });
            }

            OneTimePasswordMembershipProvider otpMembershipProvider;

            using(this.repository.Playback())
            {
                otpMembershipProvider = new OneTimePasswordMembershipProvider();
                otpMembershipProvider.Initialize(name, config);
            }

            this.repository.BackToRecordAll();
            return otpMembershipProvider;
        }

        #endregion

        #region Tests that verify that calls are dispatched to the provider

        [TestMethod]
        public void ShouldInitializeOnProvider()
        {
            this.CreateAndInitializeOneTimePasswordMembershipProvider();

            this.repository.Record().Dispose();
            this.repository.Playback().Dispose();
        }

        [TestMethod]
        public void ShouldSetApplicationNameOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.ApplicationName).SetPropertyWithArgument("/test");
            }

            using(this.repository.Playback())
            {
                otpMembershipProvider.ApplicationName = "/test";
            }
        }

        [TestMethod]
        public void ShouldGetApplicationNameOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.ApplicationName).Return("/test");
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual("/test", otpMembershipProvider.ApplicationName);
            }
        }

        [TestMethod]
        public void ShouldGetPasswordStrengthRegularExpressionOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.PasswordStrengthRegularExpression).Return("{}");
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual("{}", otpMembershipProvider.PasswordStrengthRegularExpression);
            }
        }

        [TestMethod]
        public void ShouldGetMinRequiredNonAlphanumericCharactersOnProvider()
        {
            OneTimePasswordMembershipProvider otpmembershipprovider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.MinRequiredNonAlphanumericCharacters).Return(2);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(2, otpmembershipprovider.MinRequiredNonAlphanumericCharacters);
            }
        }

        [TestMethod]
        public void ShouldGetMinRequiredPasswordLengthOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.MinRequiredPasswordLength).Return(3);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(3, otpMembershipProvider.MinRequiredPasswordLength);
            }
        }

        [TestMethod]
        public void ShouldGetPasswordFormatOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.PasswordFormat).Return(MembershipPasswordFormat.Encrypted);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(MembershipPasswordFormat.Encrypted, otpMembershipProvider.PasswordFormat);
            }
        }

        [TestMethod]
        public void ShouldGetMaxInvalidPasswordAttemptsOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.MaxInvalidPasswordAttempts).Return(4);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(4, otpMembershipProvider.MaxInvalidPasswordAttempts);
            }
        }

        [TestMethod]
        public void ShouldGetPasswordAttemptWindowOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.PasswordAttemptWindow).Return(5);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(5, otpMembershipProvider.PasswordAttemptWindow);
            }
        }

        [TestMethod]
        public void ShouldGetEnablePasswordRetrievalOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.EnablePasswordRetrieval).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.EnablePasswordRetrieval);
            }
        }

        [TestMethod]
        public void ShouldGetEnablePasswordResetOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.EnablePasswordReset).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.EnablePasswordReset);
            }
        }

        [TestMethod]
        public void ShouldGetRequiresQuestionAndAnswerOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.RequiresQuestionAndAnswer).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.RequiresQuestionAndAnswer);
            }
        }

        [TestMethod]
        public void ShouldGetRequiresUniqueEmailOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.RequiresUniqueEmail).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.RequiresUniqueEmail);
            }
        }

        [TestMethod]
        public void ShouldCreateUserOnProvider()
        {
            object providerUserKey = new object();
            MembershipCreateStatus membershipCreateStatus = MembershipCreateStatus.Success;
            MembershipUser membershipUser = new MockMembershipUser("user");

            MembershipUser expectedResult = membershipUser;
            MembershipCreateStatus expectedmembershipCreateStatus = membershipCreateStatus;

            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.CreateUser("user", "password", "email", "passwordQuestion", "passwordAnser", true, providerUserKey, out membershipCreateStatus))
                .Return(membershipUser)
                .OutRef(membershipCreateStatus);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(expectedResult, otpMembershipProvider.CreateUser("user", "password", "email", "passwordQuestion", "passwordAnser", true, providerUserKey, out membershipCreateStatus));
                Assert.AreEqual(expectedmembershipCreateStatus, expectedmembershipCreateStatus);
            }
        }

        [TestMethod]
        public void ShouldGetUserByProviderKeyOnProvider()
        {
            object providerUserKey = new object();
            MembershipUser membershipUser = new MockMembershipUser("username");
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.GetUser(providerUserKey, true)).Return(membershipUser);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(membershipUser, otpMembershipProvider.GetUser(providerUserKey, true));
            }
        }

        [TestMethod]
        public void ShouldGetUserByUserNameOnProvider()
        {
            MembershipUser membershipUser = new MockMembershipUser("username");
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.GetUser("username", true)).Return(membershipUser);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(membershipUser, otpMembershipProvider.GetUser("username", true));
            }
        }

        [TestMethod]
        public void ShouldUpdateUserOnProvider()
        {
            MembershipUser membershipUser = new MockMembershipUser("username");
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(delegate { this.membershipProvider.UpdateUser(membershipUser); });
            }

            using(this.repository.Playback())
            {
                otpMembershipProvider.UpdateUser(membershipUser);
            }
        }

        [TestMethod]
        public void ShouldGetNumberOfUsersOnlineOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.GetNumberOfUsersOnline()).Return(11);
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual(11, otpMembershipProvider.GetNumberOfUsersOnline());
            }
        }

        [TestMethod]
        public void ShouldGetGetPasswordOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.GetPassword("username", "answer")).Return("password");
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual("password", otpMembershipProvider.GetPassword("username", "answer"));
            }
        }

        [TestMethod]
        public void ShouldResetPasswordOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.ResetPassword("username", "answer")).Return("password");
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual("password", otpMembershipProvider.ResetPassword("username", "answer"));
            }
        }

        [TestMethod]
        public void ShouldGetUserNameByEmailOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.GetUserNameByEmail("email")).Return("username");
            }

            using(this.repository.Playback())
            {
                Assert.AreEqual("username", otpMembershipProvider.GetUserNameByEmail("email"));
            }
        }

        [TestMethod]
        public void ShouldUnlockUserOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.UnlockUser("username")).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.UnlockUser("username"));
            }
        }

        [TestMethod]
        public void ShouldDeleteUserOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.DeleteUser("username", true)).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.DeleteUser("username", true));
            }
        }

        [TestMethod]
        public void ShouldChangePasswordOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.ChangePassword("username", "old", "new")).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.ChangePassword("username", "old", "new"));
            }
        }

        [TestMethod]
        public void ShouldChangePasswordQuestionAndAnswerOnProvider()
        {
            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                Expect.Call(this.membershipProvider.ChangePasswordQuestionAndAnswer("username", "password", "newQ", "newA")).Return(true);
            }

            using(this.repository.Playback())
            {
                Assert.IsTrue(otpMembershipProvider.ChangePasswordQuestionAndAnswer("username", "password", "newQ", "newA"));
            }
        }

        [TestMethod]
        public void ShouldGetAllUsersOnProvider()
        {
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));

            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                int totalRecords;

                Expect.Call(this.membershipProvider.GetAllUsers(1, 2, out totalRecords))
                .Return(membershipUsers)
                .OutRef(3);
            }

            using(this.repository.Playback())
            {
                int actualTotalRecords;
                Assert.AreEqual(membershipUsers, otpMembershipProvider.GetAllUsers(1, 2, out actualTotalRecords));
                Assert.AreEqual(3, actualTotalRecords);
            }
        }

        [TestMethod]
        public void ShouldFindUsersByNameOnUser()
        {
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));

            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                int totalRecords;

                Expect.Call(this.membershipProvider.FindUsersByName("match", 1, 2, out totalRecords))
                .Return(membershipUsers)
                .OutRef(3);
            }

            using(this.repository.Playback())
            {
                int actualTotalRecords;
                Assert.AreEqual(membershipUsers, otpMembershipProvider.FindUsersByName("match", 1, 2, out actualTotalRecords));
                Assert.AreEqual(3, actualTotalRecords);
            }
        }

        [TestMethod]
        public void ShouldFindUsersByEmailOnProvider()
        {
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));

            OneTimePasswordMembershipProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();

            using(this.repository.Record())
            {
                int totalRecords;

                Expect.Call(this.membershipProvider.FindUsersByEmail("match", 1, 2, out totalRecords))
                .Return(membershipUsers)
                .OutRef(3);
            }

            using(this.repository.Playback())
            {
                int actualTotalRecords;
                Assert.AreEqual(membershipUsers, otpMembershipProvider.FindUsersByEmail("match", 1, 2, out actualTotalRecords));
                Assert.AreEqual(3, actualTotalRecords);
            }
        }

        #endregion
    }
}